package devcontainer

import (
	"archive/tar"
	"bytes"
	"context"
	"fmt"
	"math"
	"regexp"
	"strconv"
	"strings"
	"time"

	auth_model "code.gitea.io/gitea/models/auth"
	"code.gitea.io/gitea/models/db"
	devcontainer_models "code.gitea.io/gitea/models/devcontainer"
	"code.gitea.io/gitea/models/repo"
	"code.gitea.io/gitea/models/user"
	"code.gitea.io/gitea/modules/docker"
	docker_module "code.gitea.io/gitea/modules/docker"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/modules/templates"
	gitea_context "code.gitea.io/gitea/services/context"
	files_service "code.gitea.io/gitea/services/repository/files"
	"github.com/docker/docker/api/types"
	"xorm.io/builder"
)

func HasDevContainer(ctx context.Context, userID, repoID int64) (bool, error) {
	var hasDevContainer bool
	dbEngine := db.GetEngine(ctx)
	hasDevContainer, err := dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Exist()
	if err != nil {
		return hasDevContainer, err
	}
	return hasDevContainer, nil
}
func HasDevContainerConfiguration(ctx context.Context, repo *gitea_context.Repository) (bool, error) {
	_, err := FileExists(".devcontainer/devcontainer.json", repo)
	if err != nil {
		if git.IsErrNotExist(err) {
			return false, nil
		}
		return false, err
	}
	configurationString, err := GetDevcontainerConfigurationString(ctx, repo.Repository)
	if err != nil {
		return true, err
	}
	configurationModel, err := UnmarshalDevcontainerConfigContent(configurationString)
	if err != nil {
		return true, err
	}
	// 执行验证
	if errs := configurationModel.Validate(); len(errs) > 0 {
		log.Info("配置验证失败:")
		for _, err := range errs {
			fmt.Printf(" - %s\n", err.Error())
		}
		return true, fmt.Errorf("配置格式错误")
	} else {
		return true, nil
	}
}
func HasDevContainerDockerFile(ctx context.Context, repo *gitea_context.Repository) (bool, string, error) {
	_, err := FileExists(".devcontainer/devcontainer.json", repo)
	if err != nil {
		if git.IsErrNotExist(err) {
			return false, "", nil
		}
		return false, "", err
	}
	configurationString, err := GetDevcontainerConfigurationString(ctx, repo.Repository)
	if err != nil {
		return false, "", err
	}
	configurationModel, err := UnmarshalDevcontainerConfigContent(configurationString)
	if err != nil {
		return false, "", err
	}
	// 执行验证
	if errs := configurationModel.Validate(); len(errs) > 0 {
		log.Info("配置验证失败:")
		for _, err := range errs {
			fmt.Printf(" - %s\n", err.Error())
		}
		return false, "", fmt.Errorf("配置格式错误")
	} else {
		log.Info("%v", configurationModel)
		if configurationModel.Build == nil || configurationModel.Build.Dockerfile == "" {
			_, err := FileExists(".devcontainer/Dockerfile", repo)
			if err != nil {
				if git.IsErrNotExist(err) {
					return false, "", nil
				}
				return false, "", err
			}
			return true, ".devcontainer/Dockerfile", nil
		}
		_, err := FileExists(".devcontainer/"+configurationModel.Build.Dockerfile, repo)
		if err != nil {
			if git.IsErrNotExist(err) {
				_, err := FileExists(".devcontainer/Dockerfile", repo)
				if err != nil {
					if git.IsErrNotExist(err) {
						return false, "", nil
					}
					return false, "", err
				}
				return true, ".devcontainer/Dockerfile", nil
			}
			return false, "", err
		}
		return true, ".devcontainer/" + configurationModel.Build.Dockerfile, nil
	}
}
func CreateDevcontainerConfiguration(repo *repo.Repository, doer *user.User) error {

	jsonContent, err := templates.AssetFS().ReadFile("repo/devcontainer/default_devcontainer.json")
	if err != nil {
		return err
	}
	_, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, doer, &files_service.ChangeRepoFilesOptions{
		Files: []*files_service.ChangeRepoFile{
			{
				Operation:     "create",
				TreePath:      ".devcontainer/devcontainer.json",
				ContentReader: bytes.NewReader([]byte(jsonContent)),
			},
		},
		OldBranch: "main",
		NewBranch: "main",
		Message:   "add container configuration",
	})
	if err != nil {
		return err
	}
	return nil
}

func GetWebTerminalURL(ctx context.Context, userID, repoID int64) (string, error) {
	var devcontainerName string
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return "", err
	}

	dbEngine := db.GetEngine(ctx)
	_, err = dbEngine.
		Table("devcontainer").
		Select("name").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Get(&devcontainerName)
	if err != nil {
		return "", err
	}
	if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
		//k8s的逻辑
	}
	return "", nil
}

/*
-1不存在
0 已创建数据库记录
1 正在拉取镜像
2 正在创建和启动容器
3 容器安装必要工具
4 容器正在运行
5 正在提交容器更新
6 正在重启
7 正在停止
8 容器已停止
9 正在删除
10已删除
*/
func GetDevContainerStatus(ctx context.Context, userID, repoID string) (string, error) {
	var id int
	var containerName string

	var status uint16
	var realTimeStatus uint16
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return "", err
	}
	dbEngine := db.GetEngine(ctx)
	_, err = dbEngine.
		Table("devcontainer").
		Select("devcontainer_status, id, name").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Get(&status, &id, &containerName)
	if err != nil {
		return "", err
	}

	if id == 0 {
		return fmt.Sprintf("%d", -1), nil
	}

	realTimeStatus = status
	switch status {
	//正在重启
	case 6:
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			containerRealTimeStatus, err := GetDevContainerStatusFromDocker(ctx, containerName)
			if err != nil {
				return "", err
			} else if containerRealTimeStatus == "running" {
				realTimeStatus = 4
			}
		}
		break
	//正在关闭
	case 7:
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			containerRealTimeStatus, err := GetDevContainerStatusFromDocker(ctx, containerName)
			if err != nil {
				return "", err
			} else if containerRealTimeStatus == "exited" {
				realTimeStatus = 8
			} else {
				err = StopDevContainerByDocker(ctx, containerName)
				if err != nil {
					log.Info(err.Error())
				}

			}
		}
		break
	case 9:
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			isContainerNotFound, err := IsContainerNotFound(ctx, containerName)
			if err != nil {
				return "", err
			} else if isContainerNotFound {
				realTimeStatus = 10
			} else {
				err = DeleteDevContainerByDocker(ctx, containerName)
				if err != nil {
					log.Info(err.Error())
				}
			}

		}
		break
	default:
		log.Info("other status")
	}
	//状态更新
	if realTimeStatus != status {
		if realTimeStatus == 10 {
			_, err = dbEngine.Table("devcontainer").
				Where("user_id = ? AND repo_id = ? ", userID, repoID).
				Delete()
			if err != nil {
				return "", err
			}
			_, err = dbEngine.Table("devcontainer_output").
				Where("user_id = ? AND repo_id = ? ", userID, repoID).
				Delete()
			if err != nil {
				return "", err
			}
			return "-1", nil
		}
		_, err = dbEngine.Table("devcontainer").
			Where("user_id = ? AND repo_id = ? ", userID, repoID).
			Update(&devcontainer_models.Devcontainer{DevcontainerStatus: realTimeStatus})
		if err != nil {
			return "", err
		}
		_, err = dbEngine.Table("devcontainer_output").
			Where("user_id = ? AND repo_id = ? AND list_id = ?", userID, repoID, status).
			Update(&devcontainer_models.DevcontainerOutput{Status: "finished"})
		if err != nil {
			return "", err
		}
	}
	return fmt.Sprintf("%d", realTimeStatus), nil
}
func CreateDevContainer(ctx context.Context, repo *repo.Repository, doer *user.User, publicKeyList []string, isWebTerminal bool) error {
	containerName := getSanitizedDevcontainerName(doer.Name, repo.Name)

	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return err
	}
	unixTimestamp := time.Now().Unix()
	newDevcontainer := devcontainer_models.Devcontainer{
		Name:                 containerName,
		DevcontainerHost:     cfg.Section("server").Key("DOMAIN").Value(),
		DevcontainerUsername: "root",
		DevcontainerWorkDir:  "/workspace",
		DevcontainerStatus:   0,
		RepoId:               repo.ID,
		UserId:               doer.ID,
		CreatedUnix:          unixTimestamp,
		UpdatedUnix:          unixTimestamp,
	}

	dbEngine := db.GetEngine(ctx)

	_, err = dbEngine.
		Table("devcontainer").
		Insert(newDevcontainer)
	if err != nil {
		return err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", doer.ID, repo.ID).
		Get(&newDevcontainer)
	if err != nil {
		return err
	}
	go func() {
		otherCtx := context.Background()
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			imageName, err := CreateDevContainerByDockerCommand(otherCtx, &newDevcontainer, repo, publicKeyList)
			if err != nil {
				return
			}
			if !isWebTerminal {
				CreateDevContainerByDockerAPI(otherCtx, &newDevcontainer, imageName, repo, publicKeyList)
			}
		}
	}()
	return nil
}
func DeleteDevContainer(ctx context.Context, userID, repoID int64) error {
	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Get(&devContainerInfo)
	if err != nil {
		return err
	}
	_, err = dbEngine.Table("devcontainer").
		Where("user_id = ? AND repo_id = ? ", userID, repoID).
		Update(&devcontainer_models.Devcontainer{DevcontainerStatus: 9})
	if err != nil {
		return err
	}
	go func() {
		otherCtx := context.Background()
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {

			err = DeleteDevContainerByDocker(otherCtx, devContainerInfo.Name)
			if err != nil {
				log.Info(err.Error())
			}
		}
	}()
	return nil
}
func RestartDevContainer(ctx context.Context, userID, repoID int64) error {
	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Get(&devContainerInfo)
	if err != nil {
		return err
	}
	_, err = dbEngine.Table("devcontainer").
		Where("user_id = ? AND repo_id = ? ", userID, repoID).
		Update(&devcontainer_models.Devcontainer{DevcontainerStatus: 6})
	if err != nil {
		return err
	}
	go func() {
		otherCtx := context.Background()
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			err = RestartDevContainerByDocker(otherCtx, devContainerInfo.Name)
			if err != nil {
				log.Info(err.Error())
			}
		}
	}()
	return nil
}
func StopDevContainer(ctx context.Context, userID, repoID int64) error {
	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", userID, repoID).
		Get(&devContainerInfo)
	if err != nil {
		return err
	}
	_, err = dbEngine.Table("devcontainer").
		Where("user_id = ? AND repo_id = ? ", userID, repoID).
		Update(&devcontainer_models.Devcontainer{DevcontainerStatus: 7})
	if err != nil {
		return err
	}
	go func() {
		otherCtx := context.Background()
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			err = StopDevContainerByDocker(otherCtx, devContainerInfo.Name)
			if err != nil {
				log.Info(err.Error())
			}
		}
	}()
	return nil
}

func UpdateDevContainer(ctx context.Context, doer *user.User, repo *gitea_context.Repository, updateInfo *UpdateInfo) error {
	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", doer.ID, repo.Repository.ID).
		Get(&devContainerInfo)
	if err != nil {
		return err
	}
	_, err = dbEngine.Table("devcontainer").
		Where("user_id = ? AND repo_id = ? ", doer.ID, repo.Repository.ID).
		Update(&devcontainer_models.Devcontainer{DevcontainerStatus: 5})
	if err != nil {
		return err
	}
	otherCtx := context.Background()
	if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
		//k8s的逻辑
	} else {
		updateErr := UpdateDevContainerByDocker(otherCtx, &devContainerInfo, updateInfo, repo, doer)
		_, err = dbEngine.Table("devcontainer").
			Where("user_id = ? AND repo_id = ? ", doer.ID, repo.Repository.ID).
			Update(&devcontainer_models.Devcontainer{DevcontainerStatus: 4})
		if err != nil {
			return err
		}
		if updateErr != nil {
			return updateErr
		}
	}

	return nil
}
func GetTerminalCommand(ctx context.Context, userID string, repo *repo.Repository) (string, string, error) {

	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return "", "", err
	}
	_, err = dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", userID, repo.ID).
		Get(&devContainerInfo)
	if err != nil {
		return "", "", err
	}
	realTimeStatus := devContainerInfo.DevcontainerStatus
	var cmd string

	switch devContainerInfo.DevcontainerStatus {
	case 0:
		if devContainerInfo.Id > 0 {
			realTimeStatus = 1
		}
		break
	case 1:
		//正在拉取镜像，当镜像拉取成功，则状态转移
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			configurationString, err := GetDevcontainerConfigurationString(ctx, repo)
			if err != nil {
				return "", "", err
			}
			configurationModel, err := UnmarshalDevcontainerConfigContent(configurationString)
			if err != nil {
				return "", "", err
			}
			var imageName string
			if configurationModel.Build == nil || configurationModel.Build.Dockerfile == "" {
				imageName = configurationModel.Image
			} else {
				imageName = userID + "-" + fmt.Sprintf("%d", repo.ID) + "-dockerfile"
			}
			isExist, err := ImageExists(ctx, imageName)
			if err != nil {
				return "", "", err
			}
			if isExist {
				realTimeStatus = 2
			} else {
				_, err = dbEngine.Table("devcontainer_output").
					Select("command").
					Where("user_id = ? AND repo_id = ? AND list_id = ?", userID, repo.ID, realTimeStatus).
					Get(&cmd)
				if err != nil {
					return "", "", err
				}
			}
		}
		break
	case 2:
		//正在创建容器，创建容器成功，则状态转移
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑

		} else {
			exist, _, err := ContainerExists(ctx, devContainerInfo.Name)
			if err != nil {
				return "", "", err
			}
			if !exist {
				_, err = dbEngine.Table("devcontainer_output").
					Select("command").
					Where("user_id = ? AND repo_id = ? AND list_id = ?", userID, repo.ID, realTimeStatus).
					Get(&cmd)
				if err != nil {
					return "", "", err
				}
			} else {
				status, err := GetDevContainerStatusFromDocker(ctx, devContainerInfo.Name)
				if err != nil {
					return "", "", err
				}
				if status == "created" {
					//添加脚本文件
					if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
					} else {
						userNum, err := strconv.ParseInt(userID, 10, 64)
						if err != nil {
							return "", "", err
						}
						var scriptContent string
						scriptContent, err = GetCommandContent(ctx, userNum, repo)
						log.Info("command: %s", scriptContent)
						if err != nil {
							return "", "", err
						}
						// 创建 tar 归档文件
						var buf bytes.Buffer
						tw := tar.NewWriter(&buf)
						defer tw.Close()
						// 添加文件到 tar 归档
						AddFileToTar(tw, "webTerminal.sh", string(scriptContent), 0777)
						// 创建 Docker 客户端
						cli, err := docker_module.CreateDockerClient(ctx)
						if err != nil {
							return "", "", err
						}
						// 获取容器 ID
						containerID, err := docker_module.GetContainerID(cli, devContainerInfo.Name)
						if err != nil {
							return "", "", err
						}
						err = cli.CopyToContainer(ctx, containerID, "/home", bytes.NewReader(buf.Bytes()), types.CopyToContainerOptions{})
						if err != nil {
							log.Info("%v", err)
							return "", "", err
						}
					}
					realTimeStatus = 3

				}
			}

		}
		break
	case 3:
		//正在初始化容器，初始化容器成功，则状态转移
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			status, err := CheckDirExistsFromDocker(ctx, devContainerInfo.Name, devContainerInfo.DevcontainerWorkDir)
			if err != nil {
				return "", "", err
			}
			if status {
				realTimeStatus = 4
			}
		}
		break
	case 4:
		//正在连接容器
		if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
			//k8s的逻辑
		} else {
			_, err = dbEngine.Table("devcontainer_output").
				Select("command").
				Where("user_id = ? AND repo_id = ? AND list_id = ?", userID, repo.ID, realTimeStatus).
				Get(&cmd)
			if err != nil {
				return "", "", err
			}
			configurationString, err := GetDevcontainerConfigurationString(ctx, repo)
			if err != nil {
				return "", "", err
			}
			configurationModel, err := UnmarshalDevcontainerConfigContent(configurationString)
			if err != nil {
				return "", "", err
			}
			postAttachCommand := strings.TrimSpace(strings.Join(configurationModel.ParseCommand(configurationModel.PostAttachCommand), "\n"))
			if _, ok := configurationModel.PostAttachCommand.(map[string]interface{}); ok {
				// 是 map[string]interface{} 类型
				cmdObj := configurationModel.PostAttachCommand.(map[string]interface{})
				if pathValue, hasPath := cmdObj["path"]; hasPath {
					fileCommand, err := GetFileContentByPath(ctx, repo, ".devcontainer/"+pathValue.(string))
					if err != nil {
						return "", "", err
					}
					postAttachCommand += "\n" + fileCommand
				}
			}
			cmd += postAttachCommand
		}
		break
	}

	if realTimeStatus != devContainerInfo.DevcontainerStatus {
		//下一条指令
		_, err = dbEngine.Table("devcontainer_output").
			Select("command").
			Where("user_id = ? AND repo_id = ? AND list_id = ?", userID, repo.ID, realTimeStatus).
			Get(&cmd)
		if err != nil {
			return "", "", err
		}
		_, err = dbEngine.Table("devcontainer").
			Where("user_id = ? AND repo_id = ? ", userID, repo.ID).
			Update(&devcontainer_models.Devcontainer{DevcontainerStatus: realTimeStatus})
		if err != nil {
			return "", "", err
		}
	}
	return cmd, fmt.Sprintf("%d", realTimeStatus), nil
}
func GetDevContainerOutput(ctx context.Context, user_id string, repo *repo.Repository) (string, error) {
	var devContainerOutput string
	dbEngine := db.GetEngine(ctx)

	_, err := dbEngine.Table("devcontainer_output").
		Select("output").
		Where("user_id = ? AND repo_id = ? AND list_id = ?", user_id, repo.ID, 4).
		Get(&devContainerOutput)

	if err != nil {
		return "", err
	}
	if devContainerOutput != "" {
		_, err = dbEngine.Table("devcontainer_output").
			Where("user_id = ? AND repo_id = ? AND list_id = ?", user_id, repo.ID, 4).
			Update(map[string]interface{}{
				"output": "",
			})
		if err != nil {
			return "", err
		}
	}

	return devContainerOutput, nil
}
func SaveDevContainerOutput(ctx context.Context, user_id string, repo *repo.Repository, newoutput string) error {
	var devContainerOutput string
	var finalOutput string
	dbEngine := db.GetEngine(ctx)

	// 从数据库中获取现有的输出内容
	_, err := dbEngine.Table("devcontainer_output").
		Select("output").
		Where("user_id = ? AND repo_id = ? AND list_id = ?", user_id, repo.ID, 4).
		Get(&devContainerOutput)
	if err != nil {
		return err
	}
	devContainerOutput = strings.TrimSuffix(devContainerOutput, "\r\n")
	if newoutput == "\b \b" {
		finalOutput = devContainerOutput[:len(devContainerOutput)-1]
	} else {
		finalOutput = devContainerOutput + newoutput
	}
	_, err = dbEngine.Table("devcontainer_output").
		Where("user_id = ? AND repo_id = ? AND list_id = ?", user_id, repo.ID, 4).
		Update(map[string]interface{}{
			"output": finalOutput + "\r\n",
		})
	if err != nil {
		return err
	}
	return nil
}
func GetMappedPort(ctx context.Context, containerName string, port string) (uint16, error) {
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		return 0, err
	}
	if cfg.Section("k8s").Key("ENABLE").Value() == "true" {
		//k8s的逻辑
		return 0, nil
	} else {
		port, err := docker_module.GetMappedPort(ctx, containerName, port)
		if err != nil {
			return 0, err
		}
		return port, nil
	}
}
func GetDevcontainersList(ctx context.Context, doer *user.User, pageNum, pageSize int) (DevcontainerList, error) {

	// 0. 构造异常返回时的空数据
	var resultDevContainerListVO = DevcontainerList{
		Page:          0,
		PageSize:      50,
		PageTotalNum:  0,
		ItemTotalNum:  0,
		DevContainers: []devcontainer_models.Devcontainer{},
	}
	resultDevContainerListVO.UserID = doer.ID
	resultDevContainerListVO.Username = doer.Name

	paginationOption := db.ListOptions{
		Page:     pageNum,
		PageSize: pageSize,
	}

	paginationOption.ListAll = false // 强制使用分页查询，禁止一次性列举所有 devContainers
	if paginationOption.Page <= 0 {  // 未指定页码/无效页码：查询第 1 页
		paginationOption.Page = 1
	}
	if paginationOption.PageSize <= 0 || paginationOption.PageSize > 50 {
		paginationOption.PageSize = 50 // /无效页面大小/超过每页最大限制：自动调整到系统最大开发容器页面大小
	}
	resultDevContainerListVO.Page = paginationOption.Page
	resultDevContainerListVO.PageSize = paginationOption.PageSize

	// 2. SQL 条件构建

	sqlCondition := builder.Eq{"user_id": doer.ID}
	// 执行数据库事务
	err := db.WithTx(ctx, func(ctx context.Context) error {
		// 查询总数
		count, err := db.GetEngine(ctx).
			Table("devcontainer").
			Where(sqlCondition).
			Count()
		if err != nil {
			return err
		}
		resultDevContainerListVO.ItemTotalNum = count

		// 无记录直接返回
		if count == 0 {
			return nil
		}

		// 计算分页参数
		pageSize := int64(resultDevContainerListVO.PageSize)
		resultDevContainerListVO.PageTotalNum = int(math.Ceil(float64(count) / float64(pageSize)))

		// 查询分页数据
		sess := db.GetEngine(ctx).
			Table("devcontainer").
			Join("INNER", "repository", "devcontainer.repo_id = repository.id").
			Where(sqlCondition).
			OrderBy("devcontainer_id DESC").
			Select(`devcontainer.id AS devcontainer_id,
				devcontainer.name AS devcontainer_name,
				devcontainer.devcontainer_host AS devcontainer_host,
				devcontainer.devcontainer_username AS devcontainer_username,
				devcontainer.devcontainer_work_dir AS devcontainer_work_dir,
				devcontainer.repo_id AS repo_id,
				repository.name AS repo_name,
				repository.owner_name AS repo_owner_name,
				repository.description AS repo_description,
				CONCAT('/', repository.owner_name, '/', repository.name) AS repo_link`)

		resultDevContainerListVO.DevContainers = make([]devcontainer_models.Devcontainer, 0, pageSize)
		err = db.SetSessionPagination(sess, &paginationOption).
			Find(&resultDevContainerListVO.DevContainers)

		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return resultDevContainerListVO, err
	}

	return resultDevContainerListVO, nil
}
func Get_IDE_TerminalURL(ctx *gitea_context.Context, doer *user.User, repo *gitea_context.Repository) (string, error) {
	dbEngine := db.GetEngine(ctx)
	var devContainerInfo devcontainer_models.Devcontainer
	_, err := dbEngine.
		Table("devcontainer").
		Select("*").
		Where("user_id = ? AND repo_id = ?", doer.ID, repo.Repository.ID).
		Get(&devContainerInfo)
	if err != nil {
		return "", err
	}

	// 加载配置文件
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		log.Error("Get_IDE_TerminalURL: 加载配置文件失败: %v", err)
		return "", err
	}
	log.Info("Get_IDE_TerminalURL: 配置文件加载成功, ROOT_URL=%s", cfg.Section("server").Key("ROOT_URL").Value())
	var access_token string

	// 检查 session 中是否已存在 token
	if ctx.Session.Get("access_token") != nil {
		access_token = ctx.Session.Get("access_token").(string)
	} else {
		// 生成 token
		token := &auth_model.AccessToken{
			UID:  devContainerInfo.UserId,
			Name: "terminal_login_token",
		}
		exist, err := auth_model.AccessTokenByNameExists(ctx, token)
		if err != nil {
			return "", err
		}
		if exist {
			db.GetEngine(ctx).Table("access_token").Where("uid = ? AND name = ?", doer.ID, "terminal_login_token").Delete()
		}
		scope, err := auth_model.AccessTokenScope(strings.Join([]string{"write:user", "write:repository"}, ",")).Normalize()
		if err != nil {
			return "", err
		}
		token.Scope = scope
		err = auth_model.NewAccessToken(db.DefaultContext, token)
		if err != nil {
			return "", err
		}
		ctx.Session.Set("terminal_login_token", token.Token)
		access_token = token.Token
	}

	// 根据不同的代理类型获取 SSH 端口
	var port string

	if cfg.Section("k8s").Key("ENABLE").Value() == "true" {

	} else {
		mappedPort, err := docker_module.GetMappedPort(ctx, devContainerInfo.Name, "22")
		if err != nil {
			return "", err
		}
		port = fmt.Sprintf("%d", mappedPort)
	}

	// 构建并返回 URL
	return "://mengning.devstar/" +
		"openProject?host=" + repo.Repository.Name +
		"&hostname=" + devContainerInfo.DevcontainerHost +
		"&port=" + port +
		"&username=" + doer.Name +
		"&path=" + devContainerInfo.DevcontainerWorkDir +
		"&access_token=" + access_token +
		"&devstar_username=" + repo.Repository.OwnerName +
		"&devstar_domain=" + cfg.Section("server").Key("ROOT_URL").Value(), nil
}
func GetCommandContent(ctx context.Context, userId int64, repo *repo.Repository) (string, error) {
	configurationString, err := GetDevcontainerConfigurationString(ctx, repo)
	if err != nil {
		return "", err
	}
	configurationModel, err := UnmarshalDevcontainerConfigContent(configurationString)
	if err != nil {
		return "", err
	}
	onCreateCommand := strings.TrimSpace(strings.Join(configurationModel.ParseCommand(configurationModel.OnCreateCommand), "\n"))
	if _, ok := configurationModel.OnCreateCommand.(map[string]interface{}); ok {
		// 是 map[string]interface{} 类型
		cmdObj := configurationModel.OnCreateCommand.(map[string]interface{})
		if pathValue, hasPath := cmdObj["path"]; hasPath {
			fileCommand, err := GetFileContentByPath(ctx, repo, ".devcontainer/"+pathValue.(string))
			if err != nil {
				return "", err
			}
			onCreateCommand += "\n" + fileCommand
		}
	}
	updateCommand := strings.TrimSpace(strings.Join(configurationModel.ParseCommand(configurationModel.UpdateContentCommand), "\n"))
	if _, ok := configurationModel.UpdateContentCommand.(map[string]interface{}); ok {
		// 是 map[string]interface{} 类型
		cmdObj := configurationModel.UpdateContentCommand.(map[string]interface{})
		if pathValue, hasPath := cmdObj["path"]; hasPath {
			fileCommand, err := GetFileContentByPath(ctx, repo, ".devcontainer/"+pathValue.(string))
			if err != nil {
				return "", err
			}
			updateCommand += "\n" + fileCommand
		}
	}
	postCreateCommand := strings.TrimSpace(strings.Join(configurationModel.ParseCommand(configurationModel.PostCreateCommand), "\n"))
	if _, ok := configurationModel.PostCreateCommand.(map[string]interface{}); ok {
		// 是 map[string]interface{} 类型
		cmdObj := configurationModel.PostCreateCommand.(map[string]interface{})
		if pathValue, hasPath := cmdObj["path"]; hasPath {
			fileCommand, err := GetFileContentByPath(ctx, repo, ".devcontainer/"+pathValue.(string))
			if err != nil {
				return "", err
			}
			postCreateCommand += "\n" + fileCommand
		}
	}

	postStartCommand := strings.TrimSpace(strings.Join(configurationModel.ParseCommand(configurationModel.PostStartCommand), "\n"))
	if _, ok := configurationModel.PostStartCommand.(map[string]interface{}); ok {
		// 是 map[string]interface{} 类型
		cmdObj := configurationModel.PostStartCommand.(map[string]interface{})
		if pathValue, hasPath := cmdObj["path"]; hasPath {
			fileCommand, err := GetFileContentByPath(ctx, repo, ".devcontainer/"+pathValue.(string))
			if err != nil {
				return "", err
			}
			postStartCommand += "\n" + fileCommand
		}
	}
	var script []string
	scripts, err := devcontainer_models.GetScript(ctx, userId, repo.ID)
	for _, v := range scripts {
		script = append(script, v)
	}
	scriptCommand := strings.TrimSpace(strings.Join(script, "\n"))
	userCommand := scriptCommand + "\n" + onCreateCommand + "\n" + updateCommand + "\n" + postCreateCommand + "\n" + postStartCommand + "\n"
	assetFS := templates.AssetFS()
	Content_tmpl, err := assetFS.ReadFile("repo/devcontainer/devcontainer_tmpl.sh")
	if err != nil {
		return "", err
	}
	Content_start, err := assetFS.ReadFile("repo/devcontainer/devcontainer_start.sh")
	if err != nil {
		return "", err
	}
	Content_restart, err := assetFS.ReadFile("repo/devcontainer/devcontainer_restart.sh")
	if err != nil {
		return "", err
	}

	final_command := string(Content_tmpl)
	re1 := regexp.MustCompile(`\$\{` + regexp.QuoteMeta("START") + `\}|` + `\$` + regexp.QuoteMeta("START") + `\b`)
	escapedContentStart := strings.ReplaceAll(string(Content_start), `$`, `$$`)
	escapedUserCommand := strings.ReplaceAll(userCommand, `$`, `$$`)
	final_command = re1.ReplaceAllString(final_command, escapedContentStart+"\n"+escapedUserCommand)

	re1 = regexp.MustCompile(`\$RESTART\b`)
	escapedContentRestart := strings.ReplaceAll(string(Content_restart), `$`, `$$`)
	escapedPostStartCommand := strings.ReplaceAll(postStartCommand, `$`, `$$`)
	final_command = re1.ReplaceAllString(final_command, escapedContentRestart+"\n"+escapedPostStartCommand)
	return parseCommand(ctx, final_command, userId, repo)
}
func AddPublicKeyToAllRunningDevContainer(ctx context.Context, userId int64, publicKey string) error {
	// 加载配置文件
	cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
	if err != nil {
		log.Error("Get_IDE_TerminalURL: 加载配置文件失败: %v", err)
		return err
	}
	if cfg.Section("k8s").Key("ENABLE").Value() == "true" {

	} else {
		cli, err := docker.CreateDockerClient(ctx)
		if err != nil {
			return err
		}
		defer cli.Close()
		var devcontainerList []devcontainer_models.Devcontainer
		// 查询所有打开的容器
		err = db.GetEngine(ctx).
			Table("devcontainer").
			Where("user_id = ? AND devcontainer_status = ?", userId, 4).
			Find(&devcontainerList)
		if err != nil {
			return err
		}

		if len(devcontainerList) > 0 {
			// 将公钥写入这些打开的容器中
			for _, repoDevContainer := range devcontainerList {
				containerID, err := docker.GetContainerID(cli, repoDevContainer.Name)
				if err != nil {
					return err
				}
				log.Info("container id: %s, name: %s", containerID, repoDevContainer.Name)
				// 检查容器状态
				containerStatus, err := docker.GetContainerStatus(cli, containerID)
				if err != nil {
					continue
				}

				if containerStatus == "running" {
					// 只为处于运行状态的容器添加公钥
					_, err = docker.ExecCommandInContainer(ctx, cli, repoDevContainer.Name, fmt.Sprintf("echo '%s' >> ~/.ssh/authorized_keys", publicKey))
					if err != nil {
						return err
					}
				}
			}
		}
		return nil
	}
	return fmt.Errorf("unknown agent")

}
func parseCommand(ctx context.Context, command string, userId int64, repo *repo.Repository) (string, error) {
	variables, err := devcontainer_models.GetVariables(ctx, userId, repo.ID)

	var variablesName []string
	variablesCircle := checkEachVariable(variables)
	for key := range variables {
		if !variablesCircle[key] {
			variablesName = append(variablesName, key)
		}
	}
	for ContainsAnySubstring(command, variablesName) {
		for key, value := range variables {
			if variablesCircle[key] == true {
				continue
			}
			log.Info("key: %s, value: %s", key, value)
			re1 := regexp.MustCompile(`\$\{` + regexp.QuoteMeta(key) + `\}|` + `\$` + regexp.QuoteMeta(key) + `\b`)

			escapedValue := strings.ReplaceAll(value, `$`, `$$`)
			command = re1.ReplaceAllString(command, escapedValue)
			variablesName = append(variablesName, key)
		}
	}

	var userSSHPublicKeyList []string
	err = db.GetEngine(ctx).
		Table("public_key").
		Select("content").
		Where("owner_id = ?", userId).
		Find(&userSSHPublicKeyList)
	if err != nil {
		return "", err
	}
	re1 := regexp.MustCompile(`\$\{` + regexp.QuoteMeta("PUBLIC_KEY_LIST") + `\}|` + `\$` + regexp.QuoteMeta("PUBLIC_KEY_LIST") + `\b`)
	command = re1.ReplaceAllString(command, strings.Join(userSSHPublicKeyList, "\n"))
	return command, nil
}
